Executive Summary

Abstract

Introduction

Methods

Data Collection

Data was imported using the \data_gathering.RMD script. See that script for details of collection.

Data Shaping

Taking in raw data and adding a parseable timestamp while filtering on the date and client_ids.

Function Definition

Define functions to create posts per day of week graphs, and timeseries of engagement line graphs.

Additional Data Shaping for Engagement

Shape data into vertical data formats.


Attaching package: ‘chron’

The following objects are masked from ‘package:lubridate’:

    days, hours, minutes, seconds, years

Results

Summary Statistics

  • Lets start here with a table of summary statistics
[1] "tbl_df"     "tbl"        "data.frame"

Matrices plots of Engagement

First plot is aggregated engagement by content type. Second plot, it engagement by type for client(Labatt).

  • As Bud Light and Michelob ULTRA are the to companies with the highest engagement, comparison of

  • Looking at the engagement by content type we see that Labatt is garnering its most significant engagment on Photos, Video, and Links.

  • [ ] TODO: we need to compare posting activity with engagement activity (scatter plot)

Summary Plots

Horizontal stacked bar chart for total engagement comparison of all companies

reorder_size <- function(x) {
  factor(x, levels = names(sort(table(x))))
}
p <- summary_stats %>%
  filter(Engagement != "Total.Posts") %>%
  ggplot(., aes(x = Company, y = Number, fill = Engagement)) +
  geom_bar(stat = "identity") +
  xlab("") + ylab("") +
  coord_flip()
plot(p)

  • [ ] TODO: Create a scaled version of the stacked eng bar chart that is scaled by the number of fans for each bar.

Day of Week

Total posts per day of the week.

# without brand ID these are uninformative
for(i in seq_along(df_names)) {
  p <- day_of_week(df_names[i], client_names[i])
  plot(p)
}

p <- ggplot(data = all_companies_ts, aes(x = wday(timestamp, label = TRUE))) +
  geom_bar(aes(fill = ..count..)) +
  theme(legend.position = "none") +
  xlab("Day of the Week") + ylab("Number of Posts") +
  scale_fill_gradient(low = "midnightblue", high = "aquamarine4") + 
  facet_wrap(~from_name, ncol = 4) +
  ggtitle("Daily Posting Activity by brand")
plot(p)

  • What is the total number of posts?
dowDat <- select(all_companies_ts, total_engagement,from_name, timestamp)
dowDat$dow <- wday(dowDat$timestamp, label=TRUE)
dowDat <- aggregate(total_engagement~dow+from_name, data=dowDat, FUN=mean)
p <- ggplot(dowDat, aes(x = dow, y = total_engagement)) +
  geom_bar(stat="identity", aes(fill = total_engagement)) + 
  facet_grid(~from_name) + 
  ggtitle('Engagements Per Day of Week') +
  theme(legend.position = "none") +
  xlab("Day of the Week") + ylab("Number of Engagements") +
  scale_fill_gradient(low = "midnightblue", high = "aquamarine4")
plot(p)

-[ ] TODO: Create a plot for Post by engagement graphics (scatter plot). To answer the question on days with lots of posts do we get lots of engagment.

  • [] TODO: With that data we can ask what posts get the most engagment, we can look at top engagment and bottom engagements posts and what qualities they share or differ by.

  • [X] Time of day visual break down?

Engagement by Time of Day (TOD)

Timeseries Engagement

Plots for the timeseries engagement line.

for(i in seq_along(df_names)) {
  p <- timeseries_engagement(client_names_proper[i])
  plot(p)
}

Initial Visualization of engagement over time on a line

Test viz, showed spike in enegagment for Bud Light in august 2016.

all_companies_ts <- all_companies_ts %>%
  filter(from_id %in% client_ids) %>%
  mutate(month = as.Date(cut(all_companies_ts$timestamp, breaks = "month")))
ggplot(all_companies_ts, aes(x = month, y = total_engagement)) +
  geom_line(aes(group = from_name, color = factor(from_name)))

all_companies_ts %>%
  select(from_name, month, total_engagement) %>%
  group_by(from_name,month) %>%
  summarise(totEng = sum(total_engagement)) %>%
  ggplot(., aes(x = month, y = totEng)) +
   geom_point(aes(color = from_name)) +
  geom_smooth(aes(color = from_name), se = FALSE)

all_companies_ts %>%
  select(from_name, month, total_engagement) %>%
  filter(from_name != "Bud Light" ) %>%
  filter(from_name != "Michelob ULTRA") %>%
  group_by(from_name,month) %>%
  summarise(totEng = sum(total_engagement)) %>%
  ggplot(., aes(x = month, y = totEng)) +
   geom_point(aes(color = from_name)) +
   geom_smooth(aes(color = from_name), se = FALSE) +
   ggtitle("Monthly Facebook Engagement w/o Bud & MichULTRA")

  • This is an interesting drop of ~30% over the first 6 months of 2015. The brand has still not recovered from that reduction.
  • What is different about the content during this period?

  • Might be valuable to look back at the entire timeseries for periods of distinct dynamism.

Labatt Wordclouds

Removed filter because labatt does not have significant inflection point whereas previous analysis

labatt$timestamp <- date(labatt$timestamp)
labatt_clean_pre <- str_replace_all(labatt$message, "@\\w+", "")
labatt_clean_pre <- gsub("&amp", "", labatt_clean_pre)
labatt_clean_pre <- gsub("(RT|via)((?:\\b\\W*@\\w+)+)", "", labatt_clean_pre)
labatt_clean_pre <- gsub("@\\w+", "", labatt_clean_pre)
labatt_clean_pre <- gsub("[[:punct:]]", "", labatt_clean_pre)
labatt_clean_pre <- gsub("[[:digit:]]", "", labatt_clean_pre)
labatt_clean_pre <- gsub("http\\w+", "", labatt_clean_pre)
labatt_clean_pre <- gsub("[ \t]{2,}", "", labatt_clean_pre)
labatt_clean_pre <- gsub("^\\s+|\\s+$", "", labatt_clean_pre)
labatt_corpus_pre <- Corpus(VectorSource(labatt_clean_pre))
labatt_corpus_pre <- tm_map(labatt_corpus_pre, removePunctuation)
labatt_corpus_pre <- tm_map(labatt_corpus_pre, content_transformer(tolower))
labatt_corpus_pre <- tm_map(labatt_corpus_pre, removeWords, stopwords("english"))
labatt_corpus_pre <- tm_map(labatt_corpus_pre, removeWords, c("amp", "2yo", "3yo", "4yo"))
labatt_corpus_pre <- tm_map(labatt_corpus_pre, stripWhitespace)
pal <- brewer.pal(9,"YlGnBu")
pal <- pal[-(1:4)]
set.seed(123)
wordcloud(words = labatt_corpus_pre, scale=c(5,0.1), max.words=25, random.order=FALSE, 
          rot.per=0.35, use.r.layout=FALSE, colors=pal)

Point Graphs for Posts

Displays engagement per post to find outliers.

p <- ggplot(all_companies_ts, aes(x = month, y = total_engagement)) +
  geom_point(aes(color = from_name)) +
  xlab("Year") + ylab("Total Engagement") + 
  theme(legend.title=element_blank(), 
        legend.text=element_text(size=12), 
        legend.position=c(0.18, 0.77), 
        legend.background=element_rect(fill=alpha('gray', 0)))
plot(p)

Total Engagement Line

# q <- aggregate(all_companies_ts$total_engagement~all_companies_ts$month+
#                  all_companies_ts$from_name,
#                FUN=sum)
# 
# ggplot(q, aes(x = q$`all_companies_ts$month`, y = q$`all_companies_ts$total_engagement`)) +
#   geom_line(aes(color=q$`all_companies_ts$from_name`)) +
#   ylab("Total Engagement") + xlab("Year") +
#   theme(legend.title=element_blank(), 
#         legend.text=element_text(size=12), 
#         legend.position=c(0.18, 0.77), 
#         legend.background=element_rect(fill=alpha('gray', 0)))

Engagement by Company

### molson Content Over Time ###
t <- all_companies_ts %>%
  filter(., from_name == "Molson Canadian")
t <- data.frame(table(t$month, t$type))
t$Var1 <- date(t$Var1)
ggplot(t, aes(x = Var1, y = Freq, group = Var2)) +
  geom_line(aes(color=Var2)) +
  ggtitle('Molson Engagement') +
  xlab("Year") + ylab("Post Frequency") +
  theme(legend.title=element_blank(), 
        legend.text=element_text(size=12), 
        legend.position=c(0.18, 0.77), 
        legend.background=element_rect(fill=alpha('gray', 0)))

#TRISTEN'S GRAPHS!!
#Labatt Content Over Time
### Labatt Content Over Time ###
t <- all_companies_ts %>%
  filter(., from_name == "Labatt USA")
t <- data.frame(table(t$month, t$type))
t$Var1 <- date(t$Var1)
ggplot(t, aes(x = Var1, y = Freq, group = Var2)) +
  geom_line(aes(color=Var2)) +
  ggtitle('Labatt Facebook Activity') +
  xlab("Year") + ylab("Post Frequency") +
  theme(legend.title=element_blank(), 
        legend.text=element_text(size=12), 
        legend.position=c(0.18, 0.77), 
        legend.background=element_rect(fill=alpha('gray', 0)))

#Labatt Content Over Time
#MichelobULTRA Content Over Time ###
t <- all_companies_ts %>%
  filter(., from_name == "Michelob ULTRA")
t <- data.frame(table(t$month, t$type))
t$Var1 <- date(t$Var1)
ggplot(t, aes(x = Var1, y = Freq, group = Var2)) +
  geom_line(aes(color=Var2)) +
  ggtitle('Michelob ULTRA Engagement') +
  xlab("Year") + ylab("Post Frequency") +
  theme(legend.title=element_blank(), 
        legend.text=element_text(size=12), 
        legend.position=c(0.18, 0.77), 
        legend.background=element_rect(fill=alpha('gray', 0)))

  • Is this true? TODO: Verify that these are the only content types for Molson.
#Labatt Content Over Time
#Bud Light Content Over Time ###
t <- all_companies_ts %>%
  filter(., from_name == "Bud Light")
t <- data.frame(table(t$month, t$type))
t$Var1 <- date(t$Var1)
ggplot(t, aes(x = Var1, y = Freq, group = Var2)) +
  geom_line(aes(color=Var2)) +
  ggtitle('Bud Light Engagement') +
  xlab("Year") + ylab("Post Frequency") +
  theme(legend.title=element_blank(), 
        legend.text=element_text(size=12), 
        legend.position=c(0.18, 0.77), 
        legend.background=element_rect(fill=alpha('gray', 0)))

Pulling #hastags

I found an example on Stackoverflow

Experiment with Hashtag extraction

# LabattUSA_timeline %>% 
#   filter()
# 
# 
# tweets <- LabattUSA_timeline$text
# match <- regmatches(tweets,gregexpr("#[[:alnum:]]+",tweets))
# 
# # Convert the list to a corpus
# # new_corpus <- as.VCorpus(new_list)  from Stackoverflow (http://stackoverflow.com/questions/34061912/how-transform-a-list-into-a-corpus-in-r)
# 
# new_corpus <- as.VCorpus(match)
# class(new_corpus)
# inspect(new_corpus)
# 
# EnsurePackage <- function(x) {
#   # EnsurePackage(x) - Installs and loads a package if necessary
#   # Args:
#   #   x: name of package
# 
#   x <- as.character(x)
#   if (!require(x, character.only=TRUE)) {
#     install.packages(pkgs=x, repos="http://cran.r-project.org")
#     require(x, character.only=TRUE)
#   }
# }
# 
# MakeWordCloud <- function(corpus) {
#   # Make a word cloud
#   #
#   # Args:
#   #   textVec: a text vector
#   #
#   # Returns:
#   #   A word cloud created from the text vector
#   
#   EnsurePackage("tm")
#   EnsurePackage("wordcloud")
#   EnsurePackage("RColorBrewer")
#   
#   corpus <- tm_map(corpus, function(x) {
#     removeWords(x, c("via", "rt", "mt"))
#   })
#   
#   ap.tdm <- TermDocumentMatrix(corpus)
#   ap.m <- as.matrix(ap.tdm)
#   ap.v <- sort(rowSums(ap.m), decreasing=TRUE)
#   ap.d <- data.frame(word = names(ap.v), freq=ap.v)
#   table(ap.d$freq)
#   pal2 <- brewer.pal(8, "Dark2")
#   
#   wordcloud(ap.d$word, ap.d$freq, 
#             scale=c(8, .2), min.freq = 3, 
#             max.words = Inf, random.order = FALSE, 
#             rot.per = .15, colors = pal2)
# }
# 
# MakeWordCloud(new_corpus)

Mosaic Plot Experiment

  • [ ] TODO: Full timeseries of total eng by brand. (To look for seasonality) - if sports are a driver than seasonality might be important
# p <- unfiltered_ts %>%
#   summarise(jd = doy(timestamp)) %>%
#   group_by(jd) %>%
#   ggplot(aes(factor(jd),total_engagement)) +
#   geom_boxplot() + 
#   facet_grid(~ from_name)
# plot(p)
  • [ ] Populate a table of top performing posts and low performing posts - Tristen can pull shot of tweets for discussion
  • [ ] Create a data.frame with these columns brand, data, tweet, engagement (I think this is a subset of all_companies)

  • [ ] summary table of brand, month, totEng, see examples:http://leonawicz.github.io/HtmlWidgetExamples/ex_dt_sparkline.html

all_companies_ts %>%
  select(from_name, timestamp, total_engagement) %>%
  group_by(from_name, month(timestamp), year(timestamp)) %>%
  summarise(count = n(), 
            engagement = sum(total_engagement)) %>%
  ggplot(., aes(y = log(engagement), x = log(count), colour = from_name)) +
  geom_point() +
  geom_smooth(se = FALSE, method = "lm") +
  #geom_smooth(se = FALSE)
  ggtitle("Engagement vs Post Acitivity")

all_companies_ts %>%
  #filter(from_name != "Bud Light" ) %>%
  #filter(from_name != "Michelob ULTRA") %>%
  select(from_name, timestamp, total_engagement) %>%
  group_by(from_name, month(timestamp), year(timestamp)) %>%
  summarise(count = n(),
            engagement = sum(total_engagement)) %>%
  ggplot(., aes(y = engagement, x = count, colour = from_name)) +
  geom_point() +
  geom_smooth(se = FALSE, method = "lm") +
  ggtitle("Engagement vs Post Acitivity") +
  ylab("Total Engagement") + xlab("Total Monthly Posts")

  • There is a positive relationship between post activity (ie counts) and total engagement.

  • [ ] TOD vs engagement similar to post activity vs Engagement

Kevins Questions

# load('processed_data/bud_fb.RData')
# bud$total_engagement <- rowSums(bud[,9:11])
# z <- bud %>%
#   arrange(desc(total_engagement))
# head(z)
# Updated upstream

Twitter

text_clean <- function(cleanliness) {
  cleanliness <- str_replace_all(cleanliness, "@\\w+", "")
  cleanliness <- gsub("&amp", "", cleanliness)
  cleanliness <- gsub("(RT|via)((?:\\b\\W*@\\w+)+)", "", cleanliness)
  cleanliness <- gsub("@\\w+", "", cleanliness)
  cleanliness <- gsub("[[:punct:]]", "", cleanliness)
  cleanliness <- gsub("[[:digit:]]", "", cleanliness)
  cleanliness <- gsub("http\\w+", "", cleanliness)
  cleanliness <- gsub("[ \t]{2,}", "", cleanliness)
  cleanliness <- gsub("^\\s+|\\s+$", "", cleanliness)
  return(cleanliness)
}
LabattUSA_timeline$sentiment <- lapply(text_clean(LabattUSA_timeline$text), get_nrc_sentiment)
labatt_sentiment <- data.frame('created' = LabattUSA_timeline$created,
                               'text' = LabattUSA_timeline$text,
                               'sentiment' = as.character(LabattUSA_timeline$sentiment))
labatt_sentiment$score <- get_sentiment(as.character(text_clean(labatt_sentiment$text))) %>% as.numeric()
labatt_sentiment %>%
  arrange(desc(score)) %>%
  select(created, score) %>%
  tail(5)
labatt_sentiment %>%
  ggplot(aes(as_date(created), score)) +
  geom_line(size = 1) +
  geom_smooth() +
  scale_color_manual(values = colourList) +
  scale_x_date(breaks = date_breaks("3 months"), labels = date_format("%Y-%b")) +
  scale_y_continuous(name = "Sentiment\n", breaks = seq(-5, 5, by = 1)) + theme_bw() +
  ggtitle('Labatt Sentiment')

Molson_Canadian_timeline$sentiment <- lapply(text_clean(Molson_Canadian_timeline$text), get_nrc_sentiment)
molson_sentiment <- data.frame('created' = Molson_Canadian_timeline$created,
                               'text' = Molson_Canadian_timeline$text,
                               'sentiment' = as.character(Molson_Canadian_timeline$sentiment))
molson_sentiment$score <- get_sentiment(as.character(text_clean(molson_sentiment$text))) %>% as.numeric()
molson_sentiment %>%
  arrange(desc(score)) %>%
  select(created, score) %>%
  tail(5)
molson_sentiment %>%
  ggplot(aes(as_date(created), score)) +
  geom_line(size = 1) +
  geom_smooth() +
  scale_color_manual(values = colourList) +
  scale_x_date(breaks = date_breaks("3 months"), labels = date_format("%Y-%b")) +
  scale_y_continuous(name = "Sentiment\n", breaks = seq(-5, 5, by = 1)) + theme_bw() +
  ggtitle('Molson Sentiment')

budlight_timeline$sentiment <- lapply(text_clean(budlight_timeline$text), get_nrc_sentiment)
budlight_sentiment <- data.frame('created' = budlight_timeline$created,
                               'text' = budlight_timeline$text,
                               'sentiment' = as.character(budlight_timeline$sentiment))
budlight_sentiment$score <- get_sentiment(as.character(text_clean(budlight_sentiment$text))) %>% as.numeric()
budlight_sentiment %>%
  arrange(desc(score)) %>%
  select(created, score) %>%
  tail(5)
budlight_sentiment %>%
  ggplot(aes(as_date(created), score)) +
  geom_line(size = 1) +
  geom_smooth() +
  scale_color_manual(values = colourList) +
  scale_x_date(breaks = date_breaks("3 months"), labels = date_format("%Y-%b")) +
  scale_y_continuous(name = "Sentiment\n", breaks = seq(-5, 5, by = 1)) + theme_bw() +
  ggtitle('BudLight Sentiment')

MichelobULTRA_timeline$sentiment <- lapply(text_clean(MichelobULTRA_timeline$text), get_nrc_sentiment)
michelob_sentiment <- data.frame('created' = MichelobULTRA_timeline$created,
                               'text' = MichelobULTRA_timeline$text,
                               'sentiment' = as.character(MichelobULTRA_timeline$sentiment))
michelob_sentiment$score <- get_sentiment(as.character(text_clean(michelob_sentiment$text))) %>% as.numeric()
michelob_sentiment %>%
  arrange(desc(score)) %>%
  select(created, score) %>%
  tail(5)
michelob_sentiment %>%
  ggplot(aes(as_date(created), score)) +
  geom_line(size = 1) +
  geom_smooth() +
  scale_color_manual(values = colourList) +
  scale_x_date(breaks = date_breaks("3 months"), labels = date_format("%Y-%b")) +
  scale_y_continuous(name = "Sentiment\n", breaks = seq(-5, 5, by = 1)) + theme_bw() +
  ggtitle('Michelob Sentiment')

LS0tCnRpdGxlOiAiTGFiYXR0IFBsYXlib29rIEFuYWx5c2lzIgphdXRob3I6ICJXaWxkRmlnIgpkYXRlOiAnYHIgU3lzLkRhdGUoKWAnCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKc3VidGl0bGU6IFNvY2lhbCBNZWRpYSBBbmFseXNpcyB0byBzdXBwb3J0IFF1ZW5jaCBuZXcgYnVzaW5lc3MgcHJvcG9zYWwKLS0tCgojIyBFeGVjdXRpdmUgU3VtbWFyeQoKYGBge3IsIGVjaG89RkFMU0V9CiMgVGhpcyBpcyBhIGJ1bGxldGVkIHBvaW50IGxpc3Qgb2YgcHJpbWFyeSBpbnNpZ2h0cwpgYGAKCi0gTGFiYXR0IGhhcyBhIHNtYWxsIGJ1dCBsb3lhbCBmYW5iYXNlIHRoYXQgaW50ZXJhY3RzIGF0IGEgaGlnaGVyIHJhdGUgdGhhbiBvdGhlciBjb21wYW5pZXMKLSBCdWRMaWdodCcgZmFuYmFzZSBpcyBkcml2aW5nIHRoZWlyIGVuZ2FnZW1lbnQgbnVtYmVycyBkdWUgdG8gdGhlIGxhcmdlIG91dHNpemluZyB2ZXJzdXMgbGFiYXR0Ci0gTGFiYXR0IG5lZWRzIHRvIGZvY3VzIHRoZWlyIG1lc3NhZ2UgYXJvdW5kIHdoYXQncyBkcml2aW5nIGVuZ2FnZW1lbnQgaW4gdGhlaXIgc2VjdG9yIGFuZCBvdGhlciBzZWN0b3JzIGJ5IG90aGVyIGNvbXBhbmllcyBzdWNoIGFzIGZvb3RiYWxsLgoKCiMjIEFic3RyYWN0CgpgYGB7ciwgZWNobz1GQUxTRX0KIyBUaGlzIGlzIGEgdGV4dHVhbCBvdmVydmlldyBvZiBhbGwgdGhlIHdvcmsgYW5kIHRoZSBwcmltYXJ5IGZpbmRpbmdzIHdlIGZvdW5kLiAgVGhpcyBzaG91bGQgYmUgd3JpdHRlbiBmcm9tIHRoZSBjb250ZXh0IHRoYXQgYSBicmFuZCBtYW5hZ2VyIGNvdWxkIHRha2UgdGhlIHRleHQgYW5kIHBsYWNlIGluIGFuIGVtYWlsIHRvIGEgY2xpZW50CmBgYAoKCiMjIEludHJvZHVjdGlvbgoKYGBge3IsIGVjaG89RkFMU0V9CiMgVGhpcyBzZWN0aW9uIGlzIG1lYW50IHRvIGNvbnRhaW4gb3VyIG9iamVjdGl2ZXMgYW5kIGFueSBoeXBvdGhlc2VzIHdlIGFyZSB0ZXN0aW5nIChsYXN0IHBhcmFncmFwaCksIGFzIHdlbGwgYXMgYW55IGluZm9ybWF0aW9uIG9yIHN1bW1hcmllcyBvZiByZXNlYXJjaCBtYXRlcmlhbHMgd2UgdXNlZCBpbiBwcmVwYXJhdGlvbiBmb3Igb3VyIGFuYWx5c2lzIG9yIGZvciBvdXIgaW5zaWdodHMuICAKYGBgCgojIyBNZXRob2RzCgojIyMgRGF0YSBDb2xsZWN0aW9uCkRhdGEgd2FzIGltcG9ydGVkIHVzaW5nIHRoZSBgXGRhdGFfZ2F0aGVyaW5nLlJNRGAgc2NyaXB0LiAgU2VlIHRoYXQgc2NyaXB0IGZvciBkZXRhaWxzIG9mIGNvbGxlY3Rpb24uICAKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQoKbGlicyA8LSBjKCd0aWR5cicsICdicm9vbScsICdkcGx5cicsICdnZ3Bsb3QyJywgJ2dnZm9ydGlmeScsICd0aWR5dGV4dCcsICdyZWFkcicsICdzdHJpbmdyJywKICAgICAgICAgICdqc29ubGl0ZScsICdSZmFjZWJvb2snLCAndHdpdHRlUicsICdsdWJyaWRhdGUnLCAnc2NhbGVzJywgJ3dvcmRjbG91ZCcsICdTbm93YmFsbEMnLAogICAgICAgICAgJ3RtJywgJ3N5dXpoZXQnLCAndGlkeXInLCAneHRzJykKbGFwcGx5KGxpYnMsIGxpYnJhcnksIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkKcmVtb3ZlKGxpYnMpCgpmaWxlbmFtZXMgPC0gbGlzdC5maWxlcyhwYXRoID0gJ3Byb2Nlc3NlZF9kYXRhLycsIHBhdHRlcm4gPSAnKi5SRGF0YScsIGZ1bGwubmFtZXMgPSBUUlVFKQpsYXBwbHkoZmlsZW5hbWVzLCBsb2FkLCAuR2xvYmFsRW52KQpyZW1vdmUoZmlsZW5hbWVzKQoKZGZfbmFtZXMgPC0gYygnbGFiYXR0JywgJ21vbHNvbicsICd1bHRyYScsICdidWQnKQpjbGllbnRfbmFtZXMgPC0gYygnTGFiYXR0X1VTQScsICdNb2xzb25fQ2FuYWRpYW4nLCAnTWljaGVsb2JfVUxUUkEnLCAnYnVkbGlnaHQnKQpjbGllbnRfbmFtZXNfcHJvcGVyIDwtIGMoJ0xhYmF0dCBVU0EnLCAnTW9sc29uIENhbmFkaWFuJywgJ01pY2hlbG9iIFVMVFJBJywgJ0J1ZCBMaWdodCcpCmNsaWVudF9pZHMgPC0gYygxMzQzOTE4NDY3MjM1NDUsIDQyNDEwNjU2MTAwNDMwOCwgNTc5MjEzMTk4MDgsIDU0ODc2MjQ1MDk0KQoKIyBybWFya2Rvd246OnJlbmRlcignYmVlcl9hbmFseXNpcy5SbWQnLCBvdXRwdXRfZmlsZSA9ICdkb2N1bWVudHMvYmVlcl9hbmFseXNpcy5odG1sJykKYGBgCgoKIyMjIERhdGEgU2hhcGluZwoKVGFraW5nIGluIHJhdyBkYXRhIGFuZCBhZGRpbmcgYSBwYXJzZWFibGUgdGltZXN0YW1wIHdoaWxlIGZpbHRlcmluZyBvbiB0aGUgZGF0ZSBhbmQgY2xpZW50X2lkcy4KCmBgYHtyIGRhdGFfc2hhcGluZywgaW5jbHVkZSA9IEZBTFNFfQpsYWJhdHQkdGltZXN0YW1wIDwtIHltZF9obXMobGFiYXR0JGNyZWF0ZWRfdGltZSkKbGFiYXR0JHRpbWVzdGFtcCA8LSB3aXRoX3R6KGxhYmF0dCR0aW1lc3RhbXAsICJBbWVyaWNhL05ld19Zb3JrIikKCm1vbHNvbiR0aW1lc3RhbXAgPC0geW1kX2htcyhtb2xzb24kY3JlYXRlZF90aW1lKQptb2xzb24kdGltZXN0YW1wIDwtIHdpdGhfdHoobW9sc29uJHRpbWVzdGFtcCwgIkFtZXJpY2EvTmV3X1lvcmsiKQoKdWx0cmEkdGltZXN0YW1wIDwtIHltZF9obXModWx0cmEkY3JlYXRlZF90aW1lKQp1bHRyYSR0aW1lc3RhbXAgPC0gd2l0aF90eih1bHRyYSR0aW1lc3RhbXAsICJBbWVyaWNhL05ld19Zb3JrIikKCmJ1ZCR0aW1lc3RhbXAgPC0geW1kX2htcyhidWQkY3JlYXRlZF90aW1lKQpidWQkdGltZXN0YW1wIDwtIHdpdGhfdHooYnVkJHRpbWVzdGFtcCwgIkFtZXJpY2EvTmV3X1lvcmsiKQoKYWxsX2NvbXBhbmllc190cyA8LSByYmluZChsYWJhdHQsIG1vbHNvbiwgdWx0cmEsIGJ1ZCkKYWxsX2NvbXBhbmllc190cyA8LSBzdWJzZXQoYWxsX2NvbXBhbmllc190cywgc2VsZWN0ID0gLWMobWVzc2FnZSwgY3JlYXRlZF90aW1lLCBsaW5rLCBpZCkpCmFsbF9jb21wYW5pZXNfdHMkdG90YWxfZW5nYWdlbWVudCA8LSByb3dTdW1zKGFsbF9jb21wYW5pZXNfdHNbNTo3XSkKCnVuZmlsdGVyZWRfdHMgPC0gYWxsX2NvbXBhbmllc190cyAlPiUKICBmaWx0ZXIoZnJvbV9pZCAlaW4lIGNsaWVudF9pZHMpCgphbGxfY29tcGFuaWVzX3RzIDwtIGFsbF9jb21wYW5pZXNfdHMgJT4lCiAgZmlsdGVyKGZyb21faWQgJWluJSBjbGllbnRfaWRzKSAlPiUKICBmaWx0ZXIoeWVhcih0aW1lc3RhbXApICVpbiUgYygnMjAxNScsICcyMDE2JykpCgpsYWJhdHQgPC0gbGFiYXR0ICU+JQogIGZpbHRlcihmcm9tX2lkICVpbiUgY2xpZW50X2lkcykgJT4lCiAgZmlsdGVyKHllYXIodGltZXN0YW1wKSAlaW4lIGMoJzIwMTUnLCAnMjAxNicpKQoKbW9sc29uIDwtIG1vbHNvbiAlPiUKICBmaWx0ZXIoZnJvbV9pZCAlaW4lIGNsaWVudF9pZHMpICU+JQogIGZpbHRlcih5ZWFyKHRpbWVzdGFtcCkgJWluJSBjKCcyMDE1JywgJzIwMTYnKSkKCnVsdHJhIDwtIHVsdHJhICU+JQogIGZpbHRlcihmcm9tX2lkICVpbiUgY2xpZW50X2lkcykgJT4lCiAgZmlsdGVyKHllYXIodGltZXN0YW1wKSAlaW4lIGMoJzIwMTUnLCAnMjAxNicpKQoKYnVkIDwtIGJ1ZCAlPiUKICBmaWx0ZXIoZnJvbV9pZCAlaW4lIGNsaWVudF9pZHMpICU+JQogIGZpbHRlcih5ZWFyKHRpbWVzdGFtcCkgJWluJSBjKCcyMDE1JywgJzIwMTYnKSkKCiMgQnVpbGQgU3VtbWFyeSBTdGF0cyBEYXRhRnJhbWUKQ29tcGFueSA8LSBjKCdMYWJhdHQgVVNBJywgJ01vbHNvbiBDYW5hZGlhbicsICdNaWNoZWxvYiBVTFRSQScsICdCdWQgTGlnaHQnKQpDb21tZW50cyA8LSBjKHN1bShsYWJhdHQkY29tbWVudHNfY291bnQpLCBzdW0obW9sc29uJGNvbW1lbnRzX2NvdW50KSwgc3VtKHVsdHJhJGNvbW1lbnRzX2NvdW50KSwgc3VtKGJ1ZCRjb21tZW50c19jb3VudCkpCkxpa2VzIDwtIGMoc3VtKGxhYmF0dCRsaWtlc19jb3VudCksIHN1bShtb2xzb24kbGlrZXNfY291bnQpLCBzdW0odWx0cmEkbGlrZXNfY291bnQpLCBzdW0oYnVkJGxpa2VzX2NvdW50KSkKU2hhcmVzIDwtIGMoc3VtKGxhYmF0dCRzaGFyZXNfY291bnQpLCBzdW0obW9sc29uJHNoYXJlc19jb3VudCksIHN1bSh1bHRyYSRzaGFyZXNfY291bnQpLCBzdW0oYnVkJHNoYXJlc19jb3VudCkpClRvdGFsLlBvc3RzIDwtIGMobnJvdyhsYWJhdHQpLCBucm93KG1vbHNvbiksIG5yb3codWx0cmEpLCBucm93KGJ1ZCkpCnN1bW1hcnlfc3RhdHMgPC0gZGF0YS5mcmFtZShDb21wYW55LCBDb21tZW50cywgTGlrZXMsIFNoYXJlcywgVG90YWwuUG9zdHMpCmBgYAoKIyMjIEZ1bmN0aW9uIERlZmluaXRpb24KCgpEZWZpbmUgZnVuY3Rpb25zIHRvIGNyZWF0ZSBwb3N0cyBwZXIgZGF5IG9mIHdlZWsgZ3JhcGhzLCBhbmQgdGltZXNlcmllcyBvZiBlbmdhZ2VtZW50IGxpbmUgZ3JhcGhzLgoKYGBge3IgZnVuY3Rpb25zLCBpbmNsdWRlID0gRkFMU0V9CmRheV9vZl93ZWVrIDwtIGZ1bmN0aW9uKGRmLCBjbGllbnQpIHsKICByIDwtIGdldChkZikgJT4lCiAgICBmaWx0ZXIoZnJvbV9pZCAlaW4lIGNsaWVudF9pZHMpCiAgZ2dwbG90KGRhdGEgPSByLCBhZXMoeCA9IHdkYXkodGltZXN0YW1wLCBsYWJlbCA9IFRSVUUpKSkgKwogICAgZ2VvbV9iYXIoYWVzKGZpbGwgPSAuLmNvdW50Li4pKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgZXhwYW5kX2xpbWl0cyh5PWMoMCwxMDApKSArIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBjKDAsIDQwLCA4MCwgMTIwLCAxNjApKSArCiAgICB4bGFiKCJEYXkgb2YgdGhlIFdlZWsiKSArIHlsYWIoIk51bWJlciBvZiBQb3N0cyIpICsKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIm1pZG5pZ2h0Ymx1ZSIsIGhpZ2ggPSAiYXF1YW1hcmluZTQiKQp9Cgp0aW1lc2VyaWVzX2VuZ2FnZW1lbnQgPC0gZnVuY3Rpb24oY2xpZW50KSB7CiAgciA8LSBhbGxfY29tcGFuaWVzX3RzIAogIHIgPC0gZmlsdGVyKHIsIGZyb21fbmFtZSA9PSBjbGllbnQpCiAgZ2dwbG90KGRhdGEgPSByLCBhZXMoeCA9IHRpbWVzdGFtcCwgeSA9IHRvdGFsX2VuZ2FnZW1lbnQpKSArIAogICAgZ2VvbV9saW5lKHNpemUgPSAxKQp9CmBgYAoKCiMjIyBBZGRpdGlvbmFsIERhdGEgU2hhcGluZyBmb3IgRW5nYWdlbWVudAoKU2hhcGUgZGF0YSBpbnRvIHZlcnRpY2FsIGRhdGEgZm9ybWF0cy4KCmBgYHtyIGFkZHRsX2RhdGFfc2hhcGluZywgaW5jbHVkZSA9IEZBTFNFfQojIENyZWF0ZSBWZXJ0aWNhbCBzdW1tYXJ5X3N0YXRzIGZvciBMYWJhdHQKCnN1bW1hcnlfc3RhdHMgPC0gZ2F0aGVyKHN1bW1hcnlfc3RhdHMsIEVuZ2FnZW1lbnQsIE51bWJlciwgQ29tbWVudHM6VG90YWwuUG9zdHMpCmxhYmF0dF9lbmdhZ2VtZW50IDwtIGxhYmF0dCAlPiUKICBzZWxlY3QoZnJvbV9uYW1lLCB0eXBlLCBsaWtlc19jb3VudCwgY29tbWVudHNfY291bnQsIHNoYXJlc19jb3VudCkgJT4lCiAgZ2F0aGVyKGNvdW50X25hbWUsIHZhbHVlLCBsaWtlc19jb3VudDpzaGFyZXNfY291bnQpCgphbGxfZW5nYWdlbWVudCA8LSBhbGxfY29tcGFuaWVzX3RzICU+JQogIHNlbGVjdChmcm9tX25hbWUsIHR5cGUsIGxpa2VzX2NvdW50LCBjb21tZW50c19jb3VudCwgc2hhcmVzX2NvdW50KSAlPiUKICBnYXRoZXIoY291bnRfbmFtZSwgdmFsdWUsIGxpa2VzX2NvdW50OnNoYXJlc19jb3VudCkKCiMgUGxvdHMgZm9yIEVuZ2FnZW1lbnQgYnkgVHlwZSBmb3IgTGFiYXR0CmxhYmF0dF9lbmdhZ2VtZW50JHR5cGUgPC0gYXMuY2hhcmFjdGVyKGxhYmF0dF9lbmdhZ2VtZW50JHR5cGUpCmxhYmF0dF9lbmdhZ2VtZW50JHR5cGVbbGFiYXR0X2VuZ2FnZW1lbnQkdHlwZSA9PSAicGhvdG8iXSA8LSAiUGhvdG8iCgpsYWJhdHRfZW5nYWdlbWVudCR0eXBlIDwtIGFzLmNoYXJhY3RlcihsYWJhdHRfZW5nYWdlbWVudCR0eXBlKQpsYWJhdHRfZW5nYWdlbWVudCR0eXBlW2xhYmF0dF9lbmdhZ2VtZW50JHR5cGUgPT0gInZpZGVvIl0gPC0gIlZpZGVvIgoKbGFiYXR0X2VuZ2FnZW1lbnQkdHlwZSA8LSBhcy5jaGFyYWN0ZXIobGFiYXR0X2VuZ2FnZW1lbnQkdHlwZSkKbGFiYXR0X2VuZ2FnZW1lbnQkdHlwZVtsYWJhdHRfZW5nYWdlbWVudCR0eXBlID09ICJsaW5rIl0gPC0gIkxpbmsiCgpsYWJhdHRfZW5nYWdlbWVudCR0eXBlIDwtIGFzLmNoYXJhY3RlcihsYWJhdHRfZW5nYWdlbWVudCR0eXBlKQpsYWJhdHRfZW5nYWdlbWVudCR0eXBlW2xhYmF0dF9lbmdhZ2VtZW50JHR5cGUgPT0gInN0YXR1cyJdIDwtICJTdGF0dXMiCgpsYWJhdHRfZW5nYWdlbWVudCR0eXBlIDwtIGFzLmNoYXJhY3RlcihsYWJhdHRfZW5nYWdlbWVudCR0eXBlKQpsYWJhdHRfZW5nYWdlbWVudCR0eXBlW2xhYmF0dF9lbmdhZ2VtZW50JHR5cGUgPT0gIm11c2ljIl0gPC0gIk11c2ljIgoKbGFiYXR0X2VuZ2FnZW1lbnQkdHlwZSA8LSBhcy5jaGFyYWN0ZXIobGFiYXR0X2VuZ2FnZW1lbnQkdHlwZSkKbGFiYXR0X2VuZ2FnZW1lbnQkdHlwZVtsYWJhdHRfZW5nYWdlbWVudCR0eXBlID09ICJldmVudCJdIDwtICJFdmVudCIKCmxhYmF0dF9lbmdhZ2VtZW50JGNvdW50X25hbWUgPC0gYXMuY2hhcmFjdGVyKGxhYmF0dF9lbmdhZ2VtZW50JGNvdW50X25hbWUpCmxhYmF0dF9lbmdhZ2VtZW50JGNvdW50X25hbWVbbGFiYXR0X2VuZ2FnZW1lbnQkY291bnRfbmFtZSA9PSAibGlrZXNfY291bnQiXSA8LSAiTGlrZXMiCgpsYWJhdHRfZW5nYWdlbWVudCRjb3VudF9uYW1lIDwtIGFzLmNoYXJhY3RlcihsYWJhdHRfZW5nYWdlbWVudCRjb3VudF9uYW1lKQpsYWJhdHRfZW5nYWdlbWVudCRjb3VudF9uYW1lW2xhYmF0dF9lbmdhZ2VtZW50JGNvdW50X25hbWUgPT0gInNoYXJlc19jb3VudCJdIDwtICJTaGFyZXMiCgpsYWJhdHRfZW5nYWdlbWVudCRjb3VudF9uYW1lIDwtIGFzLmNoYXJhY3RlcihsYWJhdHRfZW5nYWdlbWVudCRjb3VudF9uYW1lKQpsYWJhdHRfZW5nYWdlbWVudCRjb3VudF9uYW1lW2xhYmF0dF9lbmdhZ2VtZW50JGNvdW50X25hbWUgPT0gImNvbW1lbnRzX2NvdW50Il0gPC0gIkNvbW1lbnRzIgoKIyBBbGwgRW5nYWdlbWVudAphbGxfZW5nYWdlbWVudCR0eXBlIDwtIGFzLmNoYXJhY3RlcihhbGxfZW5nYWdlbWVudCR0eXBlKQphbGxfZW5nYWdlbWVudCR0eXBlW2FsbF9lbmdhZ2VtZW50JHR5cGUgPT0gInBob3RvIl0gPC0gIlBob3RvIgoKYWxsX2VuZ2FnZW1lbnQkdHlwZSA8LSBhcy5jaGFyYWN0ZXIoYWxsX2VuZ2FnZW1lbnQkdHlwZSkKYWxsX2VuZ2FnZW1lbnQkdHlwZVthbGxfZW5nYWdlbWVudCR0eXBlID09ICJ2aWRlbyJdIDwtICJWaWRlbyIKCmFsbF9lbmdhZ2VtZW50JHR5cGUgPC0gYXMuY2hhcmFjdGVyKGFsbF9lbmdhZ2VtZW50JHR5cGUpCmFsbF9lbmdhZ2VtZW50JHR5cGVbYWxsX2VuZ2FnZW1lbnQkdHlwZSA9PSAibGluayJdIDwtICJMaW5rIgoKYWxsX2VuZ2FnZW1lbnQkdHlwZSA8LSBhcy5jaGFyYWN0ZXIoYWxsX2VuZ2FnZW1lbnQkdHlwZSkKYWxsX2VuZ2FnZW1lbnQkdHlwZVthbGxfZW5nYWdlbWVudCR0eXBlID09ICJzdGF0dXMiXSA8LSAiU3RhdHVzIgoKYWxsX2VuZ2FnZW1lbnQkdHlwZSA8LSBhcy5jaGFyYWN0ZXIoYWxsX2VuZ2FnZW1lbnQkdHlwZSkKYWxsX2VuZ2FnZW1lbnQkdHlwZVthbGxfZW5nYWdlbWVudCR0eXBlID09ICJtdXNpYyJdIDwtICJNdXNpYyIKCmFsbF9lbmdhZ2VtZW50JHR5cGUgPC0gYXMuY2hhcmFjdGVyKGFsbF9lbmdhZ2VtZW50JHR5cGUpCmFsbF9lbmdhZ2VtZW50JHR5cGVbYWxsX2VuZ2FnZW1lbnQkdHlwZSA9PSAiZXZlbnQiXSA8LSAiRXZlbnQiCgphbGxfZW5nYWdlbWVudCRjb3VudF9uYW1lIDwtIGFzLmNoYXJhY3RlcihhbGxfZW5nYWdlbWVudCRjb3VudF9uYW1lKQphbGxfZW5nYWdlbWVudCRjb3VudF9uYW1lW2FsbF9lbmdhZ2VtZW50JGNvdW50X25hbWUgPT0gImxpa2VzX2NvdW50Il0gPC0gIkxpa2VzIgoKYWxsX2VuZ2FnZW1lbnQkY291bnRfbmFtZSA8LSBhcy5jaGFyYWN0ZXIoYWxsX2VuZ2FnZW1lbnQkY291bnRfbmFtZSkKYWxsX2VuZ2FnZW1lbnQkY291bnRfbmFtZVthbGxfZW5nYWdlbWVudCRjb3VudF9uYW1lID09ICJzaGFyZXNfY291bnQiXSA8LSAiU2hhcmVzIgoKYWxsX2VuZ2FnZW1lbnQkY291bnRfbmFtZSA8LSBhcy5jaGFyYWN0ZXIoYWxsX2VuZ2FnZW1lbnQkY291bnRfbmFtZSkKYWxsX2VuZ2FnZW1lbnQkY291bnRfbmFtZVthbGxfZW5nYWdlbWVudCRjb3VudF9uYW1lID09ICJjb21tZW50c19jb3VudCJdIDwtICJDb21tZW50cyIKCmBgYAoKYGBge3IgRmVhdHVyZUVuZywgZWNobz1GQUxTRX0KIyBDcmVhdGUgYSBkYXkgb2Ygd2VlayB2ZWN0b3IKYWxsX2NvbXBhbmllc190cyRkb3cgPC0gd2RheShhbGxfY29tcGFuaWVzX3RzJHRpbWVzdGFtcCwgbGFiZWw9VFJVRSkKCiMgQ3JlYXRlIGEgdGltZSBvZiBkYXkgdmVjdG9yCmxpYnJhcnkoY2hyb24pCmFsbF9jb21wYW5pZXNfdHMkdG9kIDwtIGhvdXJzKGFsbF9jb21wYW5pZXNfdHMkdGltZXN0YW1wKQoKCgoKYGBgCgoKIyMgUmVzdWx0cwoKIyMjIFN1bW1hcnkgU3RhdGlzdGljcwoKLSBMZXRzIHN0YXJ0IGhlcmUgd2l0aCBhIHRhYmxlIG9mIHN1bW1hcnkgc3RhdGlzdGljcwpgYGB7ciBzdW1UYWJsZVByZXAsIGVjaG89RkFMU0V9CmRhdCA8LSBhc19kYXRhX2ZyYW1lKGFsbF9jb21wYW5pZXNfdHMpCmNsYXNzKGRhdCkKCmBgYAoKIyMjIE1hdHJpY2VzIHBsb3RzIG9mIEVuZ2FnZW1lbnQKCkZpcnN0IHBsb3QgaXMgYWdncmVnYXRlZCBlbmdhZ2VtZW50IGJ5IGNvbnRlbnQgdHlwZS4gU2Vjb25kIHBsb3QsIGl0IGVuZ2FnZW1lbnQgYnkgdHlwZSBmb3IgY2xpZW50KExhYmF0dCkuCgpgYGB7ciBtYXRyaXhfZW5nYWdlbWVudCwgaW5jbHVkZSA9IFRSVUUsIGVjaG8gPSBGQUxTRX0KcCA8LSBhbGxfZW5nYWdlbWVudCAlPiUKICBmaWx0ZXIodHlwZSAhPSAiTXVzaWMiKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHggPSB0eXBlLCB5ID0gY291bnRfbmFtZSkpICsgCiAgIGZhY2V0X2dyaWQofmZyb21fbmFtZSkgKwogICBzdGF0X3N1bShhZXMoZ3JvdXAgPSB2YWx1ZSwgY29sb3IgPSB0eXBlKSkgKyAKICAgc2NhbGVfc2l6ZShyYW5nZSA9IGMoNSwgMTUpKSArCiAgIHhsYWIoIlBvc3QgQ29udGVudCBUeXBlIikgKyAKICAgeWxhYigiRW5nYWdlbWVudCBUeXBlIikgKwogICBjb29yZF9mbGlwKCkgKyAKICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkgKwogICBnZ3RpdGxlKCJBZ2dyZWdhdGVkIEVuZ2FnZW1lbnQgYnkgQ29udGVudCBUeXBlICgyMDE1LVByZXNlbnQpIikKCnBsb3QocCkKYGBgCgotIEFzICpCdWQgTGlnaHQqIGFuZCAqTWljaGVsb2IgVUxUUkEqIGFyZSB0aGUgdG8gY29tcGFuaWVzIHdpdGggdGhlIGhpZ2hlc3QgZW5nYWdlbWVudCwgY29tcGFyaXNvbiBvZiAKCmBgYHtyIG1hdHJpeF9lbmdhZ2VtZW50MiwgaW5jbHVkZSA9IFRSVUUsIGVjaG8gPSBGQUxTRX0KcCA8LSBsYWJhdHRfZW5nYWdlbWVudCAlPiUKICBmaWx0ZXIodHlwZSAhPSAiTXVzaWMiKSAlPiUKICBmaWx0ZXIoZnJvbV9uYW1lID09ICJMYWJhdHQgVVNBIikgJT4lCiAgZ2dwbG90KC4sIGFlcyh4ID0gdHlwZSwgeSA9IGNvdW50X25hbWUpKSArIAogIHN0YXRfc3VtKGFlcyhncm91cCA9IHZhbHVlLCBjb2xvciA9IHR5cGUpKSArIHNjYWxlX3NpemUocmFuZ2UgPSBjKDUsIDE1KSkgKwogIHhsYWIoIlBvc3QgQ29udGVudCBUeXBlIikgKyB5bGFiKCJFbmdhZ2VtZW50IFR5cGUiKSArIAogIGNvb3JkX2ZsaXAoKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpICsKICBnZ3RpdGxlKCJMYWJhdHQgQWdnLiBFbmdhZ2VtZW50IGJ5IENvbnRlbnQgVHlwZSAoMjAxNS1QcmVzZW50KSIpCnBsb3QocCkKYGBgCgotIExvb2tpbmcgYXQgdGhlIGVuZ2FnZW1lbnQgYnkgY29udGVudCB0eXBlIHdlIHNlZSB0aGF0ICoqTGFiYXR0KiogaXMgZ2FybmVyaW5nIGl0cyBtb3N0IHNpZ25pZmljYW50IGVuZ2FnbWVudCBvbiBQaG90b3MsIFZpZGVvLCBhbmQgTGlua3MuICAKCgoKLSBbIF0gVE9ETzogd2UgbmVlZCB0byBjb21wYXJlIHBvc3RpbmcgYWN0aXZpdHkgd2l0aCBlbmdhZ2VtZW50IGFjdGl2aXR5IChzY2F0dGVyIHBsb3QpCgojIyMgU3VtbWFyeSBQbG90cwoKSG9yaXpvbnRhbCBzdGFja2VkIGJhciBjaGFydCBmb3IgdG90YWwgZW5nYWdlbWVudCBjb21wYXJpc29uIG9mIGFsbCBjb21wYW5pZXMKCmBgYHtyIHN1bW1hcnlfcGxvdHMsIGluY2x1ZGUgPSBUUlVFfQpyZW9yZGVyX3NpemUgPC0gZnVuY3Rpb24oeCkgewogIGZhY3Rvcih4LCBsZXZlbHMgPSBuYW1lcyhzb3J0KHRhYmxlKHgpKSkpCn0KcCA8LSBzdW1tYXJ5X3N0YXRzICU+JQogIGZpbHRlcihFbmdhZ2VtZW50ICE9ICJUb3RhbC5Qb3N0cyIpICU+JQogIGdncGxvdCguLCBhZXMoeCA9IENvbXBhbnksIHkgPSBOdW1iZXIsIGZpbGwgPSBFbmdhZ2VtZW50KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgeGxhYignQnJhbmQnKSArIHlsYWIoJ0VuZ2FnZW1lbnQnKSArCiAgZ2d0aXRsZSgnVG90YWwgRW5nYWdlbWVudChGYWNlYm9vayknKSArCiAgY29vcmRfZmxpcCgpCgpwbG90KHApCmBgYAoKLSBbIF0gVE9ETzogQ3JlYXRlIGEgc2NhbGVkIHZlcnNpb24gb2YgdGhlIHN0YWNrZWQgZW5nIGJhciBjaGFydCB0aGF0IGlzIHNjYWxlZCBieSB0aGUgbnVtYmVyIG9mIGZhbnMgZm9yIGVhY2ggYmFyLiAgCgoKIyMjIERheSBvZiBXZWVrCgpUb3RhbCBwb3N0cyBwZXIgZGF5IG9mIHRoZSB3ZWVrLgpgYGB7ciBkYXlfb2Zfd2VlaywgaW5jbHVkZSA9IFRSVUV9CiMgd2l0aG91dCBicmFuZCBJRCB0aGVzZSBhcmUgdW5pbmZvcm1hdGl2ZQpmb3IoaSBpbiBzZXFfYWxvbmcoZGZfbmFtZXMpKSB7CiAgcCA8LSBkYXlfb2Zfd2VlayhkZl9uYW1lc1tpXSwgY2xpZW50X25hbWVzW2ldKQogIHBsb3QocCkKfQpgYGAKCgpgYGB7ciBQb3N0c19kYXlfb2Zfd2VlaywgaW5jbHVkZSA9IFRSVUV9CnAgPC0gZ2dwbG90KGRhdGEgPSBhbGxfY29tcGFuaWVzX3RzLCBhZXMoeCA9IHdkYXkodGltZXN0YW1wLCBsYWJlbCA9IFRSVUUpKSkgKwogIGdlb21fYmFyKGFlcyhmaWxsID0gLi5jb3VudC4uKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIHhsYWIoIkRheSBvZiB0aGUgV2VlayIpICsgeWxhYigiTnVtYmVyIG9mIFBvc3RzIikgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIm1pZG5pZ2h0Ymx1ZSIsIGhpZ2ggPSAiYXF1YW1hcmluZTQiKSArIAogIGZhY2V0X3dyYXAofmZyb21fbmFtZSwgbmNvbCA9IDQpICsKICBnZ3RpdGxlKCJEYWlseSBQb3N0aW5nIEFjdGl2aXR5IGJ5IGJyYW5kIikKcGxvdChwKQpgYGAKCgotIFdoYXQgaXMgdGhlIHRvdGFsIG51bWJlciBvZiBwb3N0cz8gIApgYGB7ciBFbmdfZGF5X29mX3dlZWssIGluY2x1ZGUgPSBUUlVFfQpkb3dEYXQgPC0gc2VsZWN0KGFsbF9jb21wYW5pZXNfdHMsIHRvdGFsX2VuZ2FnZW1lbnQsZnJvbV9uYW1lLCB0aW1lc3RhbXApCmRvd0RhdCRkb3cgPC0gd2RheShkb3dEYXQkdGltZXN0YW1wLCBsYWJlbD1UUlVFKQpkb3dEYXQgPC0gYWdncmVnYXRlKHRvdGFsX2VuZ2FnZW1lbnR+ZG93K2Zyb21fbmFtZSwgZGF0YT1kb3dEYXQsIEZVTj1tZWFuKQoKcCA8LSBnZ3Bsb3QoZG93RGF0LCBhZXMoeCA9IGRvdywgeSA9IHRvdGFsX2VuZ2FnZW1lbnQpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBhZXMoZmlsbCA9IHRvdGFsX2VuZ2FnZW1lbnQpKSArIAogIGZhY2V0X2dyaWQofmZyb21fbmFtZSkgKyAKICBnZ3RpdGxlKCdFbmdhZ2VtZW50cyBQZXIgRGF5IG9mIFdlZWsnKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgeGxhYigiRGF5IG9mIHRoZSBXZWVrIikgKyB5bGFiKCJOdW1iZXIgb2YgRW5nYWdlbWVudHMiKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAibWlkbmlnaHRibHVlIiwgaGlnaCA9ICJhcXVhbWFyaW5lNCIpCnBsb3QocCkKYGBgCgotWyBdIFRPRE86IENyZWF0ZSBhIHBsb3QgZm9yIFBvc3QgYnkgZW5nYWdlbWVudCBncmFwaGljcyAoc2NhdHRlciBwbG90KS4gIFRvIGFuc3dlciB0aGUgcXVlc3Rpb24gb24gZGF5cyB3aXRoIGxvdHMgb2YgcG9zdHMgZG8gd2UgZ2V0IGxvdHMgb2YgZW5nYWdtZW50LiAKCi0gW10gVE9ETzogV2l0aCB0aGF0IGRhdGEgd2UgY2FuIGFzayB3aGF0IHBvc3RzIGdldCB0aGUgbW9zdCBlbmdhZ21lbnQsIHdlIGNhbiBsb29rIGF0IHRvcCBlbmdhZ21lbnQgYW5kIGJvdHRvbSBlbmdhZ2VtZW50cyBwb3N0cyBhbmQgd2hhdCBxdWFsaXRpZXMgdGhleSBzaGFyZSBvciBkaWZmZXIgYnkuICAKCgotIFtYXSBUaW1lIG9mIGRheSB2aXN1YWwgYnJlYWsgZG93bj8KCiMjIyBFbmdhZ2VtZW50IGJ5IFRpbWUgb2YgRGF5IChUT0QpCgpgYGB7ciBFbmdUb2QsIGVjaG89RkFMU0V9CmFsbF9jb21wYW5pZXNfdHMgJT4lCiAgc2VsZWN0KGZyb21fbmFtZSwgdG90YWxfZW5nYWdlbWVudCwgdG9kKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHk9dG90YWxfZW5nYWdlbWVudCwgeCA9IGZhY3Rvcih0b2QpKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBmYWNldF93cmFwKH5mcm9tX25hbWUpICsKICBnZ3RpdGxlKCJGYWNlYm9vayBCcmFuZCBFbmdhZ2VtZW50IGJ5IHRpbWUgb2YgZGF5IikgKwogIHlsYWIoIlRvdGFsIEVuZ2FnbWVudCIpICsgeGxhYigiVGltZSBvZiBEYXkiKQpgYGAKCmBgYHtyIEVuZ1RvZE5vQnVkb3JVbHRyYSwgZWNobz1GQUxTRX0KYWxsX2NvbXBhbmllc190cyAlPiUKICBmaWx0ZXIoZnJvbV9uYW1lICE9ICJCdWQgTGlnaHQiICkgJT4lCiAgZmlsdGVyKGZyb21fbmFtZSAhPSAiTWljaGVsb2IgVUxUUkEiKSAlPiUKICBzZWxlY3QoZnJvbV9uYW1lLCB0b3RhbF9lbmdhZ2VtZW50LCB0b2QpICU+JQogIGdncGxvdCguLCBhZXMoeT10b3RhbF9lbmdhZ2VtZW50LCB4ID0gZmFjdG9yKHRvZCkpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGZhY2V0X3dyYXAofmZyb21fbmFtZSkgKwogIGdndGl0bGUoIkZhY2Vib29rIEJyYW5kIEVuZ2FnZW1lbnQgYnkgdGltZSBvZiBkYXkgKHcvbyBCdWQgYW5kIE1pY2ggVUxUUkEpIikgKwogIHlsYWIoIlRvdGFsIEVuZ2FnbWVudCIpICsgeGxhYigiVGltZSBvZiBEYXkiKQpgYGAKCiMjIyBUaW1lc2VyaWVzIEVuZ2FnZW1lbnQgClBsb3RzIGZvciB0aGUgdGltZXNlcmllcyBlbmdhZ2VtZW50IGxpbmUuCmBgYHtyIGxpbmVfdGltZXNlcmllc19lbmdhZ2VtZW50LCBpbmNsdWRlID0gVFJVRX0KZm9yKGkgaW4gc2VxX2Fsb25nKGRmX25hbWVzKSkgewogIHAgPC0gdGltZXNlcmllc19lbmdhZ2VtZW50KGNsaWVudF9uYW1lc19wcm9wZXJbaV0pCiAgcGxvdChwKQp9CmBgYAoKIyMjIEluaXRpYWwgVmlzdWFsaXphdGlvbiBvZiBlbmdhZ2VtZW50IG92ZXIgdGltZSBvbiBhIGxpbmUKClRlc3Qgdml6LCBzaG93ZWQgc3Bpa2UgaW4gZW5lZ2FnbWVudCBmb3IgQnVkIExpZ2h0IGluIGF1Z3VzdCAyMDE2LgpgYGB7ciB0ZXN0X3ZpeiwgaW5jbHVkZSA9IFRSVUV9CmFsbF9jb21wYW5pZXNfdHMgPC0gYWxsX2NvbXBhbmllc190cyAlPiUKICBmaWx0ZXIoZnJvbV9pZCAlaW4lIGNsaWVudF9pZHMpICU+JQogIG11dGF0ZShtb250aCA9IGFzLkRhdGUoY3V0KGFsbF9jb21wYW5pZXNfdHMkdGltZXN0YW1wLCBicmVha3MgPSAibW9udGgiKSkpCgoKZ2dwbG90KGFsbF9jb21wYW5pZXNfdHMsIGFlcyh4ID0gbW9udGgsIHkgPSB0b3RhbF9lbmdhZ2VtZW50KSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBmcm9tX25hbWUsIGNvbG9yID0gZmFjdG9yKGZyb21fbmFtZSkpKQoKYGBgCgpgYGB7cn0KYWxsX2NvbXBhbmllc190cyAlPiUKICBzZWxlY3QoZnJvbV9uYW1lLCBtb250aCwgdG90YWxfZW5nYWdlbWVudCkgJT4lCiAgZ3JvdXBfYnkoZnJvbV9uYW1lLG1vbnRoKSAlPiUKICBzdW1tYXJpc2UodG90RW5nID0gc3VtKHRvdGFsX2VuZ2FnZW1lbnQpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHggPSBtb250aCwgeSA9IHRvdEVuZykpICsKICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBmcm9tX25hbWUpKSArCiAgZ2VvbV9zbW9vdGgoYWVzKGNvbG9yID0gZnJvbV9uYW1lKSwgc2UgPSBGQUxTRSkKYGBgCgoKCmBgYHtyfQphbGxfY29tcGFuaWVzX3RzICU+JQogIHNlbGVjdChmcm9tX25hbWUsIG1vbnRoLCB0b3RhbF9lbmdhZ2VtZW50KSAlPiUKICBmaWx0ZXIoZnJvbV9uYW1lICE9ICJCdWQgTGlnaHQiICkgJT4lCiAgZmlsdGVyKGZyb21fbmFtZSAhPSAiTWljaGVsb2IgVUxUUkEiKSAlPiUKICBncm91cF9ieShmcm9tX25hbWUsbW9udGgpICU+JQogIHN1bW1hcmlzZSh0b3RFbmcgPSBzdW0odG90YWxfZW5nYWdlbWVudCkpICU+JQogIGdncGxvdCguLCBhZXMoeCA9IG1vbnRoLCB5ID0gdG90RW5nKSkgKwogICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGZyb21fbmFtZSkpICsKICAgZ2VvbV9zbW9vdGgoYWVzKGNvbG9yID0gZnJvbV9uYW1lKSwgc2UgPSBGQUxTRSkgKwogICBnZ3RpdGxlKCJNb250aGx5IEZhY2Vib29rIEVuZ2FnZW1lbnQgdy9vIEJ1ZCAmIE1pY2hVTFRSQSIpCmBgYAoKLSBUaGlzIGlzIGFuIGludGVyZXN0aW5nIGRyb3Agb2YgfjMwJSBvdmVyIHRoZSBmaXJzdCA2IG1vbnRocyBvZiAyMDE1LiAgVGhlIGJyYW5kIGhhcyBzdGlsbCBub3QgcmVjb3ZlcmVkIGZyb20gdGhhdCByZWR1Y3Rpb24uICAKICAgKyBXaGF0IGlzIGRpZmZlcmVudCBhYm91dCB0aGUgY29udGVudCBkdXJpbmcgdGhpcyBwZXJpb2Q/CiAgIAotIE1pZ2h0IGJlIHZhbHVhYmxlIHRvIGxvb2sgYmFjayBhdCB0aGUgZW50aXJlIHRpbWVzZXJpZXMgZm9yIHBlcmlvZHMgb2YgIGRpc3RpbmN0IGR5bmFtaXNtLgogICAKCiMjIyBMYWJhdHQgV29yZGNsb3VkcwpSZW1vdmVkIGZpbHRlciBiZWNhdXNlIGxhYmF0dCBkb2VzIG5vdCBoYXZlIHNpZ25pZmljYW50IGluZmxlY3Rpb24gcG9pbnQgd2hlcmVhcyBwcmV2aW91cyBhbmFseXNpcwpgYGB7ciBsYWJhdHRfd29yZGNsb3VkcywgaW5jbHVkZSA9IFRSVUV9CmxhYmF0dCR0aW1lc3RhbXAgPC0gZGF0ZShsYWJhdHQkdGltZXN0YW1wKQoKbGFiYXR0X2NsZWFuX3ByZSA8LSBzdHJfcmVwbGFjZV9hbGwobGFiYXR0JG1lc3NhZ2UsICJAXFx3KyIsICIiKQpsYWJhdHRfY2xlYW5fcHJlIDwtIGdzdWIoIiZhbXAiLCAiIiwgbGFiYXR0X2NsZWFuX3ByZSkKbGFiYXR0X2NsZWFuX3ByZSA8LSBnc3ViKCIoUlR8dmlhKSgoPzpcXGJcXFcqQFxcdyspKykiLCAiIiwgbGFiYXR0X2NsZWFuX3ByZSkKbGFiYXR0X2NsZWFuX3ByZSA8LSBnc3ViKCJAXFx3KyIsICIiLCBsYWJhdHRfY2xlYW5fcHJlKQpsYWJhdHRfY2xlYW5fcHJlIDwtIGdzdWIoIltbOnB1bmN0Ol1dIiwgIiIsIGxhYmF0dF9jbGVhbl9wcmUpCmxhYmF0dF9jbGVhbl9wcmUgPC0gZ3N1YigiW1s6ZGlnaXQ6XV0iLCAiIiwgbGFiYXR0X2NsZWFuX3ByZSkKbGFiYXR0X2NsZWFuX3ByZSA8LSBnc3ViKCJodHRwXFx3KyIsICIiLCBsYWJhdHRfY2xlYW5fcHJlKQpsYWJhdHRfY2xlYW5fcHJlIDwtIGdzdWIoIlsgXHRdezIsfSIsICIiLCBsYWJhdHRfY2xlYW5fcHJlKQpsYWJhdHRfY2xlYW5fcHJlIDwtIGdzdWIoIl5cXHMrfFxccyskIiwgIiIsIGxhYmF0dF9jbGVhbl9wcmUpCgpsYWJhdHRfY29ycHVzX3ByZSA8LSBDb3JwdXMoVmVjdG9yU291cmNlKGxhYmF0dF9jbGVhbl9wcmUpKQpsYWJhdHRfY29ycHVzX3ByZSA8LSB0bV9tYXAobGFiYXR0X2NvcnB1c19wcmUsIHJlbW92ZVB1bmN0dWF0aW9uKQpsYWJhdHRfY29ycHVzX3ByZSA8LSB0bV9tYXAobGFiYXR0X2NvcnB1c19wcmUsIGNvbnRlbnRfdHJhbnNmb3JtZXIodG9sb3dlcikpCmxhYmF0dF9jb3JwdXNfcHJlIDwtIHRtX21hcChsYWJhdHRfY29ycHVzX3ByZSwgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygiZW5nbGlzaCIpKQpsYWJhdHRfY29ycHVzX3ByZSA8LSB0bV9tYXAobGFiYXR0X2NvcnB1c19wcmUsIHJlbW92ZVdvcmRzLCBjKCJhbXAiLCAiMnlvIiwgIjN5byIsICI0eW8iKSkKbGFiYXR0X2NvcnB1c19wcmUgPC0gdG1fbWFwKGxhYmF0dF9jb3JwdXNfcHJlLCBzdHJpcFdoaXRlc3BhY2UpCgpwYWwgPC0gYnJld2VyLnBhbCg5LCJZbEduQnUiKQpwYWwgPC0gcGFsWy0oMTo0KV0Kc2V0LnNlZWQoMTIzKQoKd29yZGNsb3VkKHdvcmRzID0gbGFiYXR0X2NvcnB1c19wcmUsIHNjYWxlPWMoNSwwLjEpLCBtYXgud29yZHM9MjUsIHJhbmRvbS5vcmRlcj1GQUxTRSwgCiAgICAgICAgICByb3QucGVyPTAuMzUsIHVzZS5yLmxheW91dD1GQUxTRSwgY29sb3JzPXBhbCkKYGBgCgojIyMgUG9pbnQgR3JhcGhzIGZvciBQb3N0cwpEaXNwbGF5cyBlbmdhZ2VtZW50IHBlciBwb3N0IHRvIGZpbmQgb3V0bGllcnMuCmBgYHtyIHBvaW50X2VuZ2FnZW1lbnQsIGluY2x1ZGUgPSBUUlVFfQpwIDwtIGdncGxvdChhbGxfY29tcGFuaWVzX3RzLCBhZXMoeCA9IG1vbnRoLCB5ID0gdG90YWxfZW5nYWdlbWVudCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGZyb21fbmFtZSkpICsKICB4bGFiKCJZZWFyIikgKyB5bGFiKCJUb3RhbCBFbmdhZ2VtZW50IikgKyAKICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj1jKDAuMTgsIDAuNzcpLCAKICAgICAgICBsZWdlbmQuYmFja2dyb3VuZD1lbGVtZW50X3JlY3QoZmlsbD1hbHBoYSgnZ3JheScsIDApKSkKcGxvdChwKQpgYGAKCiMjIyBUb3RhbCBFbmdhZ2VtZW50IExpbmUKYGBge3IgdG90YWxfZW5nYWdlbWVudF9saW5lLCBpbmNsdWRlID0gVFJVRX0KIyBxIDwtIGFnZ3JlZ2F0ZShhbGxfY29tcGFuaWVzX3RzJHRvdGFsX2VuZ2FnZW1lbnR+YWxsX2NvbXBhbmllc190cyRtb250aCsKIyAgICAgICAgICAgICAgICAgIGFsbF9jb21wYW5pZXNfdHMkZnJvbV9uYW1lLAojICAgICAgICAgICAgICAgIEZVTj1zdW0pCiMgCiMgZ2dwbG90KHEsIGFlcyh4ID0gcSRgYWxsX2NvbXBhbmllc190cyRtb250aGAsIHkgPSBxJGBhbGxfY29tcGFuaWVzX3RzJHRvdGFsX2VuZ2FnZW1lbnRgKSkgKwojICAgZ2VvbV9saW5lKGFlcyhjb2xvcj1xJGBhbGxfY29tcGFuaWVzX3RzJGZyb21fbmFtZWApKSArCiMgICB5bGFiKCJUb3RhbCBFbmdhZ2VtZW50IikgKyB4bGFiKCJZZWFyIikgKwojICAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwgCiMgICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIAojICAgICAgICAgbGVnZW5kLnBvc2l0aW9uPWMoMC4xOCwgMC43NyksIAojICAgICAgICAgbGVnZW5kLmJhY2tncm91bmQ9ZWxlbWVudF9yZWN0KGZpbGw9YWxwaGEoJ2dyYXknLCAwKSkpCmBgYAoKYGBge3J9CgpgYGAKCgojIyMgRW5nYWdlbWVudCBieSBDb21wYW55CmBgYHtyIGVuZ2FnZW1lbnRfYnlfY29tcGFueSwgaW5jbHVkZSA9IFRSVUV9CiMjIyBtb2xzb24gQ29udGVudCBPdmVyIFRpbWUgIyMjCnQgPC0gYWxsX2NvbXBhbmllc190cyAlPiUKICBmaWx0ZXIoLiwgZnJvbV9uYW1lID09ICJNb2xzb24gQ2FuYWRpYW4iKQp0IDwtIGRhdGEuZnJhbWUodGFibGUodCRtb250aCwgdCR0eXBlKSkKCnQkVmFyMSA8LSBkYXRlKHQkVmFyMSkKZ2dwbG90KHQsIGFlcyh4ID0gVmFyMSwgeSA9IEZyZXEsIGdyb3VwID0gVmFyMikpICsKICBnZW9tX2xpbmUoYWVzKGNvbG9yPVZhcjIpKSArCiAgZ2d0aXRsZSgnTW9sc29uIEVuZ2FnZW1lbnQnKSArCiAgeGxhYigiWWVhciIpICsgeWxhYigiUG9zdCBGcmVxdWVuY3kiKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCAKICAgICAgICBsZWdlbmQucG9zaXRpb249YygwLjE4LCAwLjc3KSwgCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQ9ZWxlbWVudF9yZWN0KGZpbGw9YWxwaGEoJ2dyYXknLCAwKSkpCmBgYAoKCgoKCmBgYHtyfQojVFJJU1RFTidTIEdSQVBIUyEhCiNMYWJhdHQgQ29udGVudCBPdmVyIFRpbWUKCiMjIyBMYWJhdHQgQ29udGVudCBPdmVyIFRpbWUgIyMjCnQgPC0gYWxsX2NvbXBhbmllc190cyAlPiUKICBmaWx0ZXIoLiwgZnJvbV9uYW1lID09ICJMYWJhdHQgVVNBIikKdCA8LSBkYXRhLmZyYW1lKHRhYmxlKHQkbW9udGgsIHQkdHlwZSkpCgp0JFZhcjEgPC0gZGF0ZSh0JFZhcjEpCmdncGxvdCh0LCBhZXMoeCA9IFZhcjEsIHkgPSBGcmVxLCBncm91cCA9IFZhcjIpKSArCiAgZ2VvbV9saW5lKGFlcyhjb2xvcj1WYXIyKSkgKwogIGdndGl0bGUoJ0xhYmF0dCBGYWNlYm9vayBBY3Rpdml0eScpICsKICB4bGFiKCJZZWFyIikgKyB5bGFiKCJQb3N0IEZyZXF1ZW5jeSIpICsKICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj1jKDAuMTgsIDAuNzcpLCAKICAgICAgICBsZWdlbmQuYmFja2dyb3VuZD1lbGVtZW50X3JlY3QoZmlsbD1hbHBoYSgnZ3JheScsIDApKSkKYGBgCgpgYGB7cn0KI0xhYmF0dCBDb250ZW50IE92ZXIgVGltZQoKI01pY2hlbG9iVUxUUkEgQ29udGVudCBPdmVyIFRpbWUgIyMjCnQgPC0gYWxsX2NvbXBhbmllc190cyAlPiUKICBmaWx0ZXIoLiwgZnJvbV9uYW1lID09ICJNaWNoZWxvYiBVTFRSQSIpCnQgPC0gZGF0YS5mcmFtZSh0YWJsZSh0JG1vbnRoLCB0JHR5cGUpKQoKdCRWYXIxIDwtIGRhdGUodCRWYXIxKQpnZ3Bsb3QodCwgYWVzKHggPSBWYXIxLCB5ID0gRnJlcSwgZ3JvdXAgPSBWYXIyKSkgKwogIGdlb21fbGluZShhZXMoY29sb3I9VmFyMikpICsKICBnZ3RpdGxlKCdNaWNoZWxvYiBVTFRSQSBFbmdhZ2VtZW50JykgKwogIHhsYWIoIlllYXIiKSArIHlsYWIoIlBvc3QgRnJlcXVlbmN5IikgKwogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPWMoMC4xOCwgMC43NyksIAogICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kPWVsZW1lbnRfcmVjdChmaWxsPWFscGhhKCdncmF5JywgMCkpKQpgYGAKCgotIElzIHRoaXMgdHJ1ZT8gIFRPRE86IFZlcmlmeSB0aGF0IHRoZXNlIGFyZSB0aGUgb25seSBjb250ZW50IHR5cGVzIGZvciBNb2xzb24uCgpgYGB7cn0KI0xhYmF0dCBDb250ZW50IE92ZXIgVGltZQoKI0J1ZCBMaWdodCBDb250ZW50IE92ZXIgVGltZSAjIyMKdCA8LSBhbGxfY29tcGFuaWVzX3RzICU+JQogIGZpbHRlciguLCBmcm9tX25hbWUgPT0gIkJ1ZCBMaWdodCIpCnQgPC0gZGF0YS5mcmFtZSh0YWJsZSh0JG1vbnRoLCB0JHR5cGUpKQoKdCRWYXIxIDwtIGRhdGUodCRWYXIxKQpnZ3Bsb3QodCwgYWVzKHggPSBWYXIxLCB5ID0gRnJlcSwgZ3JvdXAgPSBWYXIyKSkgKwogIGdlb21fbGluZShhZXMoY29sb3I9VmFyMikpICsKICBnZ3RpdGxlKCdCdWQgTGlnaHQgRW5nYWdlbWVudCcpICsKICB4bGFiKCJZZWFyIikgKyB5bGFiKCJQb3N0IEZyZXF1ZW5jeSIpICsKICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj1jKDAuMTgsIDAuNzcpLCAKICAgICAgICBsZWdlbmQuYmFja2dyb3VuZD1lbGVtZW50X3JlY3QoZmlsbD1hbHBoYSgnZ3JheScsIDApKSkKYGBgCgoKCiMjIyBQdWxsaW5nICNoYXN0YWdzCgpJIGZvdW5kIGFuIGV4YW1wbGUgb24gW1N0YWNrb3ZlcmZsb3ddKGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMjcxNjgyMjYvZXh0cmFjdGluZy1oYXNodGFncy1mcm9tLXR3ZWV0cykKCjwhLS0gPiB0d2VldHMgPC0gYygiTmV3IFIgam9iOiBTdGF0aXN0aWNhbCBhbmQgTWV0aG9kb2xvZ2ljYWwgQ29uc3VsdGFudCBhdCB0aGUgQ2VudGVyIGZvciBPcGVuIFNjaWVuY2UgaHR0cDovL3d3dy5yLXVzZXJzLmNvbS9qb2JzL3N0YXRpc3RpY2FsLW1ldGhvZG9sb2dpY2FsLWNvbnN1bHRhbnQtY2VudGVyLW9wZW4tc2NpZW5jZS8g4oCmICNyc3RhdHMgI2pvYnMiLCJOZXcgUiBqb2I6IFJlc2VhcmNoIEVuZ2luZWVyL0FwcGxpZWQgUmVzZWFyY2hlciBhdCBlQmF5IGh0dHA6Ly93d3cuci11c2Vycy5jb20vam9icy9yZXNlYXJjaC1lbmdpbmVlcmFwcGxpZWQtcmVzZWFyY2hlci1lYmF5LyDigKYgI3JzdGF0cyAjam9icyIpIC0tPgo8IS0tID4gbWF0Y2ggPC0gcmVnbWF0Y2hlcyh0d2VldHMsZ3JlZ2V4cHIoIiNbWzphbG51bTpdXSsiLHR3ZWV0cykpIC0tPgo8IS0tID4gbWF0Y2ggLS0+CjwhLS0gW1sxXV0gLS0+CjwhLS0gWzFdICIjcnN0YXRzIiAiI2pvYnMiICAgLS0+Cgo8IS0tIFtbMl1dIC0tPgo8IS0tIFsxXSAiI3JzdGF0cyIgIiNqb2JzIiAgIC0tPgo8IS0tID4gdW5saXN0KG1hdGNoKSAtLT4KPCEtLSBbMV0gIiNyc3RhdHMiICIjam9icyIgICAiI3JzdGF0cyIgIiNqb2JzIiAgIC0tPgoKCiMjIyBFeHBlcmltZW50IHdpdGggSGFzaHRhZyBleHRyYWN0aW9uCmBgYHtyIGhhc2hFeHRyYWN0LCBldmFsPUZBTFNFfQojIExhYmF0dFVTQV90aW1lbGluZSAlPiUgCiMgICBmaWx0ZXIoKQojIAojIAojIHR3ZWV0cyA8LSBMYWJhdHRVU0FfdGltZWxpbmUkdGV4dAojIG1hdGNoIDwtIHJlZ21hdGNoZXModHdlZXRzLGdyZWdleHByKCIjW1s6YWxudW06XV0rIix0d2VldHMpKQojIAojICMgQ29udmVydCB0aGUgbGlzdCB0byBhIGNvcnB1cwojICMgbmV3X2NvcnB1cyA8LSBhcy5WQ29ycHVzKG5ld19saXN0KSAgZnJvbSBTdGFja292ZXJmbG93IChodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzM0MDYxOTEyL2hvdy10cmFuc2Zvcm0tYS1saXN0LWludG8tYS1jb3JwdXMtaW4tcikKIyAKIyBuZXdfY29ycHVzIDwtIGFzLlZDb3JwdXMobWF0Y2gpCiMgY2xhc3MobmV3X2NvcnB1cykKIyBpbnNwZWN0KG5ld19jb3JwdXMpCiMgCiMgRW5zdXJlUGFja2FnZSA8LSBmdW5jdGlvbih4KSB7CiMgICAjIEVuc3VyZVBhY2thZ2UoeCkgLSBJbnN0YWxscyBhbmQgbG9hZHMgYSBwYWNrYWdlIGlmIG5lY2Vzc2FyeQojICAgIyBBcmdzOgojICAgIyAgIHg6IG5hbWUgb2YgcGFja2FnZQojIAojICAgeCA8LSBhcy5jaGFyYWN0ZXIoeCkKIyAgIGlmICghcmVxdWlyZSh4LCBjaGFyYWN0ZXIub25seT1UUlVFKSkgewojICAgICBpbnN0YWxsLnBhY2thZ2VzKHBrZ3M9eCwgcmVwb3M9Imh0dHA6Ly9jcmFuLnItcHJvamVjdC5vcmciKQojICAgICByZXF1aXJlKHgsIGNoYXJhY3Rlci5vbmx5PVRSVUUpCiMgICB9CiMgfQojIAojIE1ha2VXb3JkQ2xvdWQgPC0gZnVuY3Rpb24oY29ycHVzKSB7CiMgICAjIE1ha2UgYSB3b3JkIGNsb3VkCiMgICAjCiMgICAjIEFyZ3M6CiMgICAjICAgdGV4dFZlYzogYSB0ZXh0IHZlY3RvcgojICAgIwojICAgIyBSZXR1cm5zOgojICAgIyAgIEEgd29yZCBjbG91ZCBjcmVhdGVkIGZyb20gdGhlIHRleHQgdmVjdG9yCiMgICAKIyAgIEVuc3VyZVBhY2thZ2UoInRtIikKIyAgIEVuc3VyZVBhY2thZ2UoIndvcmRjbG91ZCIpCiMgICBFbnN1cmVQYWNrYWdlKCJSQ29sb3JCcmV3ZXIiKQojICAgCiMgICBjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgZnVuY3Rpb24oeCkgewojICAgICByZW1vdmVXb3Jkcyh4LCBjKCJ2aWEiLCAicnQiLCAibXQiKSkKIyAgIH0pCiMgICAKIyAgIGFwLnRkbSA8LSBUZXJtRG9jdW1lbnRNYXRyaXgoY29ycHVzKQojICAgYXAubSA8LSBhcy5tYXRyaXgoYXAudGRtKQojICAgYXAudiA8LSBzb3J0KHJvd1N1bXMoYXAubSksIGRlY3JlYXNpbmc9VFJVRSkKIyAgIGFwLmQgPC0gZGF0YS5mcmFtZSh3b3JkID0gbmFtZXMoYXAudiksIGZyZXE9YXAudikKIyAgIHRhYmxlKGFwLmQkZnJlcSkKIyAgIHBhbDIgPC0gYnJld2VyLnBhbCg4LCAiRGFyazIiKQojICAgCiMgICB3b3JkY2xvdWQoYXAuZCR3b3JkLCBhcC5kJGZyZXEsIAojICAgICAgICAgICAgIHNjYWxlPWMoOCwgLjIpLCBtaW4uZnJlcSA9IDMsIAojICAgICAgICAgICAgIG1heC53b3JkcyA9IEluZiwgcmFuZG9tLm9yZGVyID0gRkFMU0UsIAojICAgICAgICAgICAgIHJvdC5wZXIgPSAuMTUsIGNvbG9ycyA9IHBhbDIpCiMgfQojIAojIE1ha2VXb3JkQ2xvdWQobmV3X2NvcnB1cykKYGBgCgojIyMgTW9zYWljIFBsb3QgRXhwZXJpbWVudAoKCi0gWyBdIFRPRE86IEZ1bGwgdGltZXNlcmllcyBvZiB0b3RhbCBlbmcgYnkgYnJhbmQuICAoVG8gbG9vayBmb3Igc2Vhc29uYWxpdHkpIC0gaWYgc3BvcnRzIGFyZSBhIGRyaXZlciB0aGFuIHNlYXNvbmFsaXR5IG1pZ2h0IGJlIGltcG9ydGFudCAKCmBgYHtyfQojIHAgPC0gdW5maWx0ZXJlZF90cyAlPiUKIyAgIHN1bW1hcmlzZShqZCA9IGRveSh0aW1lc3RhbXApKSAlPiUKIyAgIGdyb3VwX2J5KGpkKSAlPiUKIyAgIGdncGxvdChhZXMoZmFjdG9yKGpkKSx0b3RhbF9lbmdhZ2VtZW50KSkgKwojICAgZ2VvbV9ib3hwbG90KCkgKyAKIyAgIGZhY2V0X2dyaWQofiBmcm9tX25hbWUpCiMgcGxvdChwKQpgYGAKCi0gWyBdIFBvcHVsYXRlIGEgdGFibGUgb2YgdG9wIHBlcmZvcm1pbmcgcG9zdHMgYW5kIGxvdyBwZXJmb3JtaW5nIHBvc3RzIC0gVHJpc3RlbiBjYW4gcHVsbCBzaG90IG9mIHR3ZWV0cyBmb3IgZGlzY3Vzc2lvbgotIFsgXSBDcmVhdGUgYSBkYXRhLmZyYW1lIHdpdGggdGhlc2UgY29sdW1ucyBicmFuZCwgZGF0YSwgdHdlZXQsIGVuZ2FnZW1lbnQgKEkgdGhpbmsgdGhpcyBpcyBhIHN1YnNldCBvZiBhbGxfY29tcGFuaWVzKQoKCi0gWyBdIHN1bW1hcnkgdGFibGUgb2YgYnJhbmQsIG1vbnRoLCB0b3RFbmcsIHNlZSBleGFtcGxlczpodHRwOi8vbGVvbmF3aWN6LmdpdGh1Yi5pby9IdG1sV2lkZ2V0RXhhbXBsZXMvZXhfZHRfc3BhcmtsaW5lLmh0bWwKCgpgYGB7cn0KYWxsX2NvbXBhbmllc190cyAlPiUKICBzZWxlY3QoZnJvbV9uYW1lLCB0aW1lc3RhbXAsIHRvdGFsX2VuZ2FnZW1lbnQpICU+JQogIGdyb3VwX2J5KGZyb21fbmFtZSwgbW9udGgodGltZXN0YW1wKSwgeWVhcih0aW1lc3RhbXApKSAlPiUKICBzdW1tYXJpc2UoY291bnQgPSBuKCksIAogICAgICAgICAgICBlbmdhZ2VtZW50ID0gc3VtKHRvdGFsX2VuZ2FnZW1lbnQpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHkgPSBsb2coZW5nYWdlbWVudCksIHggPSBsb2coY291bnQpLCBjb2xvdXIgPSBmcm9tX25hbWUpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChzZSA9IEZBTFNFLCBtZXRob2QgPSAibG0iKSArCiAgI2dlb21fc21vb3RoKHNlID0gRkFMU0UpCiAgZ2d0aXRsZSgiRW5nYWdlbWVudCB2cyBQb3N0IEFjaXRpdml0eSIpCmBgYAoKCgoKCmBgYHtyfQphbGxfY29tcGFuaWVzX3RzICU+JQogICNmaWx0ZXIoZnJvbV9uYW1lICE9ICJCdWQgTGlnaHQiICkgJT4lCiAgI2ZpbHRlcihmcm9tX25hbWUgIT0gIk1pY2hlbG9iIFVMVFJBIikgJT4lCiAgc2VsZWN0KGZyb21fbmFtZSwgdGltZXN0YW1wLCB0b3RhbF9lbmdhZ2VtZW50KSAlPiUKICBncm91cF9ieShmcm9tX25hbWUsIG1vbnRoKHRpbWVzdGFtcCksIHllYXIodGltZXN0YW1wKSkgJT4lCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpLAogICAgICAgICAgICBlbmdhZ2VtZW50ID0gc3VtKHRvdGFsX2VuZ2FnZW1lbnQpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHkgPSBlbmdhZ2VtZW50LCB4ID0gY291bnQsIGNvbG91ciA9IGZyb21fbmFtZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKHNlID0gRkFMU0UsIG1ldGhvZCA9ICJsbSIpICsKICBnZ3RpdGxlKCJFbmdhZ2VtZW50IHZzIFBvc3QgQWNpdGl2aXR5IikgKwogIHlsYWIoIlRvdGFsIEVuZ2FnZW1lbnQiKSArIHhsYWIoIlRvdGFsIE1vbnRobHkgUG9zdHMiKQpgYGAKCi0gVGhlcmUgaXMgYSBwb3NpdGl2ZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBwb3N0IGFjdGl2aXR5IChpZSBjb3VudHMpIGFuZCB0b3RhbCBlbmdhZ2VtZW50LiAgCgoKCi0gWyBdIFRPRCB2cyBlbmdhZ2VtZW50IHNpbWlsYXIgdG8gcG9zdCBhY3Rpdml0eSB2cyBFbmdhZ2VtZW50CgoKIyMjIEtldmlucyBRdWVzdGlvbnMgCmBgYHtyIGtldmluc19xdWVzdGlvbnMsIGluY2x1ZGUgPSBUUlVFfQojIGxvYWQoJ3Byb2Nlc3NlZF9kYXRhL2J1ZF9mYi5SRGF0YScpCiMgYnVkJHRvdGFsX2VuZ2FnZW1lbnQgPC0gcm93U3VtcyhidWRbLDk6MTFdKQojIHogPC0gYnVkICU+JQojICAgYXJyYW5nZShkZXNjKHRvdGFsX2VuZ2FnZW1lbnQpKQojIGhlYWQoeikKIyBVcGRhdGVkIHVwc3RyZWFtCmBgYAoKCiMjIFR3aXR0ZXIKYGBge3IgdHdpdHRlciBzZW50aW1lbnQsIGluY2x1ZGUgPSBUUlVFfQoKdGV4dF9jbGVhbiA8LSBmdW5jdGlvbihjbGVhbmxpbmVzcykgewogIGNsZWFubGluZXNzIDwtIHN0cl9yZXBsYWNlX2FsbChjbGVhbmxpbmVzcywgIkBcXHcrIiwgIiIpCiAgY2xlYW5saW5lc3MgPC0gZ3N1YigiJmFtcCIsICIiLCBjbGVhbmxpbmVzcykKICBjbGVhbmxpbmVzcyA8LSBnc3ViKCIoUlR8dmlhKSgoPzpcXGJcXFcqQFxcdyspKykiLCAiIiwgY2xlYW5saW5lc3MpCiAgY2xlYW5saW5lc3MgPC0gZ3N1YigiQFxcdysiLCAiIiwgY2xlYW5saW5lc3MpCiAgY2xlYW5saW5lc3MgPC0gZ3N1YigiW1s6cHVuY3Q6XV0iLCAiIiwgY2xlYW5saW5lc3MpCiAgY2xlYW5saW5lc3MgPC0gZ3N1YigiW1s6ZGlnaXQ6XV0iLCAiIiwgY2xlYW5saW5lc3MpCiAgY2xlYW5saW5lc3MgPC0gZ3N1YigiaHR0cFxcdysiLCAiIiwgY2xlYW5saW5lc3MpCiAgY2xlYW5saW5lc3MgPC0gZ3N1YigiWyBcdF17Mix9IiwgIiIsIGNsZWFubGluZXNzKQogIGNsZWFubGluZXNzIDwtIGdzdWIoIl5cXHMrfFxccyskIiwgIiIsIGNsZWFubGluZXNzKQogIHJldHVybihjbGVhbmxpbmVzcykKfQpMYWJhdHRVU0FfdGltZWxpbmUkc2VudGltZW50IDwtIGxhcHBseSh0ZXh0X2NsZWFuKExhYmF0dFVTQV90aW1lbGluZSR0ZXh0KSwgZ2V0X25yY19zZW50aW1lbnQpCmxhYmF0dF9zZW50aW1lbnQgPC0gZGF0YS5mcmFtZSgnY3JlYXRlZCcgPSBMYWJhdHRVU0FfdGltZWxpbmUkY3JlYXRlZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICd0ZXh0JyA9IExhYmF0dFVTQV90aW1lbGluZSR0ZXh0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3NlbnRpbWVudCcgPSBhcy5jaGFyYWN0ZXIoTGFiYXR0VVNBX3RpbWVsaW5lJHNlbnRpbWVudCkpCmxhYmF0dF9zZW50aW1lbnQkc2NvcmUgPC0gZ2V0X3NlbnRpbWVudChhcy5jaGFyYWN0ZXIodGV4dF9jbGVhbihsYWJhdHRfc2VudGltZW50JHRleHQpKSkgJT4lIGFzLm51bWVyaWMoKQpsYWJhdHRfc2VudGltZW50ICU+JQogIGFycmFuZ2UoZGVzYyhzY29yZSkpICU+JQogIHNlbGVjdChjcmVhdGVkLCBzY29yZSkgJT4lCiAgdGFpbCg1KQoKbGFiYXR0X3NlbnRpbWVudCAlPiUKICBnZ3Bsb3QoYWVzKGFzX2RhdGUoY3JlYXRlZCksIHNjb3JlKSkgKwogIGdlb21fbGluZShzaXplID0gMSkgKwogIGdlb21fc21vb3RoKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvdXJMaXN0KSArCiAgc2NhbGVfeF9kYXRlKGJyZWFrcyA9IGRhdGVfYnJlYWtzKCIzIG1vbnRocyIpLCBsYWJlbHMgPSBkYXRlX2Zvcm1hdCgiJVktJWIiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlNlbnRpbWVudFxuIiwgYnJlYWtzID0gc2VxKC01LCA1LCBieSA9IDEpKSArIHRoZW1lX2J3KCkgKwogIGdndGl0bGUoJ0xhYmF0dCBTZW50aW1lbnQnKQoKCk1vbHNvbl9DYW5hZGlhbl90aW1lbGluZSRzZW50aW1lbnQgPC0gbGFwcGx5KHRleHRfY2xlYW4oTW9sc29uX0NhbmFkaWFuX3RpbWVsaW5lJHRleHQpLCBnZXRfbnJjX3NlbnRpbWVudCkKbW9sc29uX3NlbnRpbWVudCA8LSBkYXRhLmZyYW1lKCdjcmVhdGVkJyA9IE1vbHNvbl9DYW5hZGlhbl90aW1lbGluZSRjcmVhdGVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3RleHQnID0gTW9sc29uX0NhbmFkaWFuX3RpbWVsaW5lJHRleHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnc2VudGltZW50JyA9IGFzLmNoYXJhY3RlcihNb2xzb25fQ2FuYWRpYW5fdGltZWxpbmUkc2VudGltZW50KSkKbW9sc29uX3NlbnRpbWVudCRzY29yZSA8LSBnZXRfc2VudGltZW50KGFzLmNoYXJhY3Rlcih0ZXh0X2NsZWFuKG1vbHNvbl9zZW50aW1lbnQkdGV4dCkpKSAlPiUgYXMubnVtZXJpYygpCm1vbHNvbl9zZW50aW1lbnQgJT4lCiAgYXJyYW5nZShkZXNjKHNjb3JlKSkgJT4lCiAgc2VsZWN0KGNyZWF0ZWQsIHNjb3JlKSAlPiUKICB0YWlsKDUpCgptb2xzb25fc2VudGltZW50ICU+JQogIGdncGxvdChhZXMoYXNfZGF0ZShjcmVhdGVkKSwgc2NvcmUpKSArCiAgZ2VvbV9saW5lKHNpemUgPSAxKSArCiAgZ2VvbV9zbW9vdGgoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG91ckxpc3QpICsKICBzY2FsZV94X2RhdGUoYnJlYWtzID0gZGF0ZV9icmVha3MoIjMgbW9udGhzIiksIGxhYmVscyA9IGRhdGVfZm9ybWF0KCIlWS0lYiIpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiU2VudGltZW50XG4iLCBicmVha3MgPSBzZXEoLTUsIDUsIGJ5ID0gMSkpICsgdGhlbWVfYncoKSArCiAgZ2d0aXRsZSgnTW9sc29uIFNlbnRpbWVudCcpCgpidWRsaWdodF90aW1lbGluZSRzZW50aW1lbnQgPC0gbGFwcGx5KHRleHRfY2xlYW4oYnVkbGlnaHRfdGltZWxpbmUkdGV4dCksIGdldF9ucmNfc2VudGltZW50KQpidWRsaWdodF9zZW50aW1lbnQgPC0gZGF0YS5mcmFtZSgnY3JlYXRlZCcgPSBidWRsaWdodF90aW1lbGluZSRjcmVhdGVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3RleHQnID0gYnVkbGlnaHRfdGltZWxpbmUkdGV4dCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdzZW50aW1lbnQnID0gYXMuY2hhcmFjdGVyKGJ1ZGxpZ2h0X3RpbWVsaW5lJHNlbnRpbWVudCkpCmJ1ZGxpZ2h0X3NlbnRpbWVudCRzY29yZSA8LSBnZXRfc2VudGltZW50KGFzLmNoYXJhY3Rlcih0ZXh0X2NsZWFuKGJ1ZGxpZ2h0X3NlbnRpbWVudCR0ZXh0KSkpICU+JSBhcy5udW1lcmljKCkKYnVkbGlnaHRfc2VudGltZW50ICU+JQogIGFycmFuZ2UoZGVzYyhzY29yZSkpICU+JQogIHNlbGVjdChjcmVhdGVkLCBzY29yZSkgJT4lCiAgdGFpbCg1KQoKYnVkbGlnaHRfc2VudGltZW50ICU+JQogIGdncGxvdChhZXMoYXNfZGF0ZShjcmVhdGVkKSwgc2NvcmUpKSArCiAgZ2VvbV9saW5lKHNpemUgPSAxKSArCiAgZ2VvbV9zbW9vdGgoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG91ckxpc3QpICsKICBzY2FsZV94X2RhdGUoYnJlYWtzID0gZGF0ZV9icmVha3MoIjMgbW9udGhzIiksIGxhYmVscyA9IGRhdGVfZm9ybWF0KCIlWS0lYiIpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiU2VudGltZW50XG4iLCBicmVha3MgPSBzZXEoLTUsIDUsIGJ5ID0gMSkpICsgdGhlbWVfYncoKSArCiAgZ2d0aXRsZSgnQnVkTGlnaHQgU2VudGltZW50JykKCk1pY2hlbG9iVUxUUkFfdGltZWxpbmUkc2VudGltZW50IDwtIGxhcHBseSh0ZXh0X2NsZWFuKE1pY2hlbG9iVUxUUkFfdGltZWxpbmUkdGV4dCksIGdldF9ucmNfc2VudGltZW50KQptaWNoZWxvYl9zZW50aW1lbnQgPC0gZGF0YS5mcmFtZSgnY3JlYXRlZCcgPSBNaWNoZWxvYlVMVFJBX3RpbWVsaW5lJGNyZWF0ZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAndGV4dCcgPSBNaWNoZWxvYlVMVFJBX3RpbWVsaW5lJHRleHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnc2VudGltZW50JyA9IGFzLmNoYXJhY3RlcihNaWNoZWxvYlVMVFJBX3RpbWVsaW5lJHNlbnRpbWVudCkpCm1pY2hlbG9iX3NlbnRpbWVudCRzY29yZSA8LSBnZXRfc2VudGltZW50KGFzLmNoYXJhY3Rlcih0ZXh0X2NsZWFuKG1pY2hlbG9iX3NlbnRpbWVudCR0ZXh0KSkpICU+JSBhcy5udW1lcmljKCkKbWljaGVsb2Jfc2VudGltZW50ICU+JQogIGFycmFuZ2UoZGVzYyhzY29yZSkpICU+JQogIHNlbGVjdChjcmVhdGVkLCBzY29yZSkgJT4lCiAgdGFpbCg1KQoKbWljaGVsb2Jfc2VudGltZW50ICU+JQogIGdncGxvdChhZXMoYXNfZGF0ZShjcmVhdGVkKSwgc2NvcmUpKSArCiAgZ2VvbV9saW5lKHNpemUgPSAxKSArCiAgZ2VvbV9zbW9vdGgoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG91ckxpc3QpICsKICBzY2FsZV94X2RhdGUoYnJlYWtzID0gZGF0ZV9icmVha3MoIjMgbW9udGhzIiksIGxhYmVscyA9IGRhdGVfZm9ybWF0KCIlWS0lYiIpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiU2VudGltZW50XG4iLCBicmVha3MgPSBzZXEoLTUsIDUsIGJ5ID0gMSkpICsgdGhlbWVfYncoKSArCiAgZ2d0aXRsZSgnTWljaGVsb2IgU2VudGltZW50JykKCmBgYAoK